package ljl.alg.wangzheng_camp.round1.stack_and_queue;

/**
 * 我操这个 easy 好难！
 * 跟它杠上了
 */
public class _03_01_3_in_1 {
    
    /**
     * 我尼玛
     * 过了！
     */
    static class TripleInOne {
        
        int len;
        int maxSize;
        int[] data;
        int l0, l1, l2;
        
        public TripleInOne(int stackSize) {
            maxSize = stackSize;
            len = stackSize << 2;
            data = new int[len];
        }
        
        int getIndex(int stackNum) {
            return switch (stackNum) {
                case 0 -> l0;
                case 1 -> l1;
                case 2 -> l2;
                default -> 0;
            };
        }
        
        int getAndIncIndex(int stackNum, boolean inc) {
            return switch (stackNum) {
                case 0 -> inc ? l0++ : --l0;
                case 1 -> inc ? l1++ : --l1;
                case 2 -> inc ? l2++ : --l2;
                default -> 0;
            };
        }
        
        public void push(int stackNum, int value) {
            if (getIndex(stackNum) == maxSize) return;
            int index = getAndIncIndex(stackNum, true);
            data[(index << 2) | stackNum] = value;
        }
        
        public int pop(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            int index = getAndIncIndex(stackNum, false);
            return data[(index << 2) | stackNum];
        }
        
        public int peek(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            int index = getIndex(stackNum) - 1;
            return data[(index << 2) | stackNum];
        }
        
        public boolean isEmpty(int stackNum) {
            return getIndex(stackNum) == 0;
        }
    }
    
    /**
     * 傻逼
     * 投机取巧
     * <p>
     * 不但用二维数组，还额外用了一个数组，去你妈的！
     * 脑瘫！
     */
    class TripleInOne3 {
        int[][] stack;
        int[] indexes = new int[3];
        int size;
        
        TripleInOne3(int size) {
            this.size = size;
            stack = new int[3][size];
        }
        
        void push(int stackNum, int value) {
            if (indexes[stackNum] == size) return;
            stack[stackNum][indexes[stackNum]++] = value;
        }
        
        int pop(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            return stack[stackNum][--indexes[stackNum]];
        }
        
        int peek(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            return stack[stackNum][indexes[stackNum] - 1];
        }
        
        boolean isEmpty(int stackNum) {
            return indexes[stackNum] == 0;
        }
    }
    
    /**
     * 用单个数组，但是也不太符合题意
     * 因为它用了一个数组来记录下标
     *
     * 思路是在 0 size 2size 这三个地方记录数据
     *
     */
    class TripleInOne4 {
        int[] data;
        int[] offsets = new int[3];
        int size;
        TripleInOne4(int size) {
            this.size = size;
            data = new int[size * 3];
            for (int i = 0; i < 3; i++) {
                offsets[i] = size * i;
            }
        }
        void push(int stackNum, int value) {
            if (offsets[stackNum] == (stackNum + 1) * size) return;
            data[offsets[stackNum]++] = value;
        }
    
        int pop(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            return data[--offsets[stackNum]];
        }
    
        int peek(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            return data[offsets[stackNum] - 1];
        }
    
        boolean isEmpty(int stackNum) {
            return offsets[stackNum] == size * stackNum;
        }
        
    }
    
    /**
     * 纯正、完全符合题意的解
     * 比我的也更优
     *
     * ["TripleInOne", "push", "push", "pop", "pop", "pop", "isEmpty"]
     * [[1], [0, 1], [0, 2], [0], [0], [0], [0]]
     *
     * 感觉数组这块我掌握的很差很差
     * 下标总是搞不清楚
     *
     * */
    static class TripleInOne5 {
        int[] data;
        int size;
        TripleInOne5(int size) {
            this.size = size;
            data = new int[3 * size + 3];
            data[0] = 0; data[1] = 1; data[2] = 2;
        }
        void push(int stackNum, int value) {
            int idx = data[stackNum];
            if (idx - stackNum == size * 3) return;
            data[data[stackNum] += 3] = value;
        }
    
        int pop(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            int res = data[data[stackNum]];
            data[stackNum] -= 3;
            return res;
        }
    
        int peek(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            return data[data[stackNum]];
        }
    
        boolean isEmpty(int stackNum) {
            return data[stackNum] == stackNum;
        }
    }
    
    
    /**
     * 这个设计的非常的晦涩
     * 不过完全符合题意
     * <p>
     * 其它的不是使用二维数组，就是使用两个一维数组，无法无天！
     */
    class TripleInOne2 {
        int[] p;
        
        TripleInOne2(int stackSize) {
            p = new int[3 * stackSize + 4];
            p[0] = stackSize;
            p[1] = 1;
            p[2] = 2;
            p[3] = 3;
        }
        
        void push(int stackNum, int value) {
            if (p[++stackNum % 4] > 3 * p[0]) return;
            p[stackNum % 4] += 3;
            p[p[stackNum % 4]] = value;
        }
        
        int pop(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            int ret = p[p[++stackNum % 4]];
            p[stackNum % 4] -= 3;
            return ret;
        }
        
        int peek(int stackNum) {
            if (isEmpty(stackNum)) return -1;
            stackNum += 1;
            return p[p[stackNum % 4]];
        }
        
        boolean isEmpty(int stackNum) {
            return p[(stackNum + 1) % 4] < 4;
        }
    }
}
